public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():V public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():2 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():V public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():6 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():2 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():< public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():+ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():* public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():@ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():V public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():X public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():X public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():2 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():2 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():V public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():@ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():+ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():K public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():K public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():V public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():2 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():─ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():| public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():% public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():V public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():G public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():U public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():\ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():+ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():8 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():z public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():4 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():3 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():0 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():1 public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():— public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():/ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():P public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():- public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():L public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():T public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():F public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():M public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():J public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():I public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():W public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():H public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():N public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():O public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():D public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():E public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():R public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():B public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():Y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():. public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():A public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():S public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():C public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():? public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():w public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():j public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():[ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():' public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():> public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():] public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():v public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():y public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():: public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():b public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():! public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():f public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():= public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():m public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():{ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():" public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():& public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():h public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():_ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():q public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():u public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():a public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():l public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():( public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():s public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():r public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():i public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():g public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():x public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():p public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():c public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():d public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():, public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():$ public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():t public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():o public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():k public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():e public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():n public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():) public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():; public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():} public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs(): public function ajax_atc_load_candidates(): void { // Minimal security: just require login. // The run_id came from the portal dropdown (scoped to this ATC's runs). // We return HTTP 200 always so old $.post callbacks can handle errors gracefully. if ( ! is_user_logged_in() ) { wp_send_json_success( [ 'candidates' => [] ] ); } $rid = absint( $_POST['run_id'] ?? 0 ); if ( ! $rid ) { wp_send_json_success( [ 'candidates' => [] ] ); } global $wpdb; $p = $wpdb->prefix . 'tcm_'; // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared $candidates = $wpdb->get_results( "SELECT c.id, c.full_name_en, c.full_name_vi, c.email, c.phone, c.national_id, e.id as enrolment_id, e.status as enrolment_status, e.enrolled_at FROM {$p}enrolments e JOIN {$p}candidates c ON c.id = e.candidate_id WHERE e.course_run_id = {$rid} AND e.status != 'cancelled' ORDER BY c.full_name_en ASC" ) ?: []; wp_send_json_success( [ 'candidates' => $candidates ] ); } public function ajax_atc_cert_runs():